// 长度和序号并不相关，因为存在归档命令！长度代表当前序列的长度，序号代表当前最大序号，0长度数据的情况下，当前序号为-1
package scmd

import (
	"errors"
	"sort"
	"strconv"

	"gitee.com/kimsoso/go-utils/sofile"
)

func NewCommands(path string) *MCommands {
	_cmds := &MCommands{}

	_cmds.path = path
	_cmds.cmds = map[string]*MCommand{}

	var err error
	_cmds.blocks, err = sofile.NewBlockfile(path, _cmds.cmds)
	if err != nil {
		panic(errors.New("create blocks error"))
	}
	_cmds.setCurseq()
	return _cmds
}

// 只能用在客户端向服务器传输文件的处理过程中
func (ms *MCommands) Add(val *MCommand) (index int, err error) {
	index = ms.GetNextSeqNum()
	key := strconv.Itoa(index)

	err = ms.blocks.Add(key, val)
	if err == nil {
		ms.curseq += 1
	}
	return
}

func (ms *MCommands) SorttedKeys() (keys []int) {
	keys = make([]int, 0, ms.GetLen())

	cmds := ms.GetBlocks()
	for key := range cmds {
		k, _ := strconv.Atoi(key)
		keys = append(keys, k)
	}

	sort.Ints(keys)
	return
}

func (ms *MCommands) Get(index int) *MCommand {
	key := strconv.Itoa(index)
	val, ok := ms.blocks.Get(key)
	if !ok {
		return nil
	} else {
		return val.(*MCommand)
	}
}
func (ms *MCommands) GetLen() int {
	return ms.blocks.GetLen()
}

func (ms *MCommands) Delete(key string) error {
	return ms.blocks.Delete(key)
}

func (ms *MCommands) GetBlocks() map[string]*MCommand {
	return ms.blocks.GetBlocks().(map[string]*MCommand)
}

func (ms *MCommands) Update(index int, val *MCommand) error {
	key := strconv.Itoa(index)
	err := ms.blocks.Update(key, val)
	return err
}

func (ms *MCommands) BatchLoad(cmds map[string]*MCommand) error {
	err := ms.blocks.BatchLoad(cmds)
	if err == nil {
		// ms.setFiles()
		ms.setCurseq()
	}
	return err
}

func (ms *MCommands) GetCommands(from int) (out map[string]*MCommand) {
	out = map[string]*MCommand{}

	if ms.GetCurSeqNum() < from {
		return
	}

	cmds := ms.GetBlocks()
	for k, cmd := range cmds {
		if cmd.Ck >= from {
			out[k] = cmd
		}
	}

	return
}

func (ms *MCommands) setCurseq() int {
	keys := ms.SorttedKeys()
	if len(keys) > 0 {
		ms.curseq = keys[len(keys)-1]
	} else {
		ms.curseq = -1
	}
	return ms.curseq
}

func (ms *MCommands) GetMinSeqNum() int {
	keys := ms.SorttedKeys()
	if len(keys) > 0 {
		return keys[0]
	} else {
		return -1
	}
}

func (ms *MCommands) GetCurSeqNum() int {
	return ms.curseq
}

func (ms *MCommands) GetNextSeqNum() int {
	return ms.curseq + 1
}

func (ms *MCommands) Destroy() {
	ms.blocks.Destroy()
	ms.curseq = -1
}

func (ms *MCommands) Clean() {
	ms.blocks.Clean()
	ms.curseq = -1
}
